#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include "Symbole.h"
#include <iostream>
using namespace std;


#include "NoeudVisitor.h"
#include "Valeur.h"
#include <typeinfo>

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre ( string nomFich ) :
        ls ( nomFich ), ts()
{
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse()
{
    arbre=programme();
    cout << "Syntaxe correcte." << endl;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme()
{
// <programme> ::= debut <seqInst> fin FIN_FICHIER

    sauterSymCour ( DEBUT );
    Noeud* si = seqInst();
    sauterSymCour ( FIN );
    testerSymCour ( "<FINDEFICHIER>" );
    return si;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst()
{
// <seqInst> ::= <inst> ; { <inst> ; }
    NoeudSeqInst* si = new NoeudSeqInst();
    do
    {
        si->ajouteInstruction ( inst() );
        sauterSymCour ( ";" );
    }
    while ( ( ls.getSymCour() =="<VARIABLE>" ) || ( ls.getSymCour() ==TANTQUE ) ||
            ( ls.getSymCour() ==REPETER ) || ( ls.getSymCour() ==SI ) ||
            ( ls.getSymCour() ==POUR ) || ( ls.getSymCour() ==LIRE ) ||
            ( ls.getSymCour() ==INT ) || ( ls.getSymCour() ==FLOAT ) ||
            ( ls.getSymCour() ==CHAR ) || ( ls.getSymCour() ==STRING ) ||
            ( ls.getSymCour() ==ECRIRE ) );
    /*} while  (ls.getSymCour()!=FIN && ls.getSymCour()!=FINTANTQUE &&
    ls.getSymCour()!=JUSQUA && ls.getSymCour()!=FINSI &&
    ls.getSymCour()!=SINON && ls.getSymCour()!=SINONSI &&
    ls.getSymCour()!=FINPOUR);*/
    // (ls.getSymCour()!="fin" || ls.getSymCour()!="fintantque" || ls.getSymCour()!="finsi" || ls.getSymCour()!="sinon" || ls.getSymCour()!="sinonsi");
    // tant que le symbole courant est un debut possible d'instruction...
    //while (ls.getSymCour()=="<VARIABLE>");

    return si;
}

////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::inst() {
// <inst> ::= <affectation>

	affectation();
}*/


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst()
//    <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter> | <instLire> | <instEcrire>
{
    if ( ls.getSymCour() =="<VARIABLE>" )
        return affectation();
    else if ( ls.getSymCour() ==INT || ls.getSymCour() ==FLOAT || ls.getSymCour() ==STRING || ls.getSymCour() ==CHAR ) // on lance la "conditionr qui contiendra elle-meme des instructions. (condition = ExpBool)
        return declaration();
    else if ( ls.getSymCour() ==SI ) // on lance la "conditionr qui contiendra elle-meme des instructions. (condition = ExpBool)
        return instSi();
    else if ( ls.getSymCour() ==TANTQUE ) // idem que if
        return instTq();
    else if ( ls.getSymCour() ==REPETER ) // idem que if
        return instRepeter();
    else if ( ls.getSymCour() ==POUR ) // idem que if
        return instPour();
    else if ( ls.getSymCour() ==LIRE ) // instruction pour lire une variable au clavier. (accepte que des <VARIABLE>
        return instLire();
    else if ( ls.getSymCour() ==ECRIRE ) // instruction pour ecrire a l'ecran des variable, entier, chaine.
        return instEcrire();
    else
        erreur ( "<inst>" );
    return NULL;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instSi()
//  <instSi> ::= si ( <expBoolOu> ) <seqInst> { sinonsi ( <expBoolOu> ) <seqInst> }
//  [ sinon <seqInst> ] finsi
{
    Noeud* suivant = NULL;
    Noeud* exp = NULL;
    Noeud* seqinst = NULL;
    Noeud* si = NULL;
    if ( ls.getSymCour() ==SI )
    {

        sauterSymCour ( SI );
        sauterSymCour ( "(" );
        exp = expBoolOu();
        sauterSymCour ( ")" );
        seqinst = seqInst();
        suivant = instSi();
        //NoeudSi* si = new NoeudSi(exp,seqinst, fact);
        //NoeudSi* pres =si;
        //	if (suivant == NULL)
        sauterSymCour ( FINSI );
        si = new NoeudSi ( exp,seqinst,suivant );
    }
    else if ( ls.getSymCour() ==SINONSI )
    {

        sauterSymCour ( SINONSI );
        sauterSymCour ( "(" );
        exp = expBoolOu();
        sauterSymCour ( ")" );
        seqinst = seqInst();
        suivant = instSi();
        //NoeudSi* sinonsi = new NoeudSi(exp,seqinst,fact);
        //	pres->setSuivant(sinonsi);
        //	pres = sinonsi;
        si = new NoeudSi ( exp,seqinst,suivant );
    }
    else if ( ls.getSymCour() ==SINON )
    {

        ls.suivant();
        seqinst = seqInst();
        exp = ts.chercheAjoute ( Symbole ( "1" ) );
        //fact=ts.chercheAjoute(Symbole("1"));
        //	NoeudSi* sinon = new NoeudSi(ts.chercheAjoute(Symbole("1")),seqinst,fact);
        //	pres->setSuivant(sinon);
        si = new NoeudSi ( exp,seqinst,suivant );
    }
    //else {
    //	sauterSymCour(FINSI);
    //	cout << "erreur" << endl;
    //	si = NULL;
    //exit(0);
    //}

    return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instTq()
// <instTq> ::= tantque ( <expBool> ) <seqInst> fintantque
{
    sauterSymCour ( TANTQUE );
    sauterSymCour ( "(" );
    Noeud* exp = expBoolOu();
    sauterSymCour ( ")" );
    Noeud* seqinst = seqInst();
    sauterSymCour ( FINTANTQUE );
    return new NoeudTantQue ( exp,seqinst );
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instPour()
// <instPour> ::= pour ( affectation ; <expBool>; affectation ) <seqInst> finpour
{
    sauterSymCour ( POUR );
    sauterSymCour ( "(" );
    Noeud* aff = affectation();
    sauterSymCour ( ";" );
    Noeud* exp = expBoolOu();
    sauterSymCour ( ";" );
    Noeud* aff2 = affectation();
    sauterSymCour ( ")" );
    Noeud* seqinst = seqInst();
    sauterSymCour ( FINPOUR );
    return new NoeudPour ( aff,aff2,exp,seqinst );
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instRepeter()
// <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
{
    sauterSymCour ( REPETER );
    Noeud* seqinst = seqInst();
    sauterSymCour ( JUSQUA );
    sauterSymCour ( "(" );
    Noeud* exp = expBoolOu();
    sauterSymCour ( ")" );
    return new NoeudRepeter ( exp,seqinst );
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instLire() //<instLire> ::= lire ( <variable> )
{
    Noeud* fact = NULL;
    sauterSymCour ( LIRE );
    sauterSymCour ( "(" );
    if ( ls.getSymCour() =="<VARIABLE>" )
    {
        fact = facteur();
        sauterSymCour ( ")" );
    }
    else
        erreur ( "<variable>" );
    return new NoeudLire ( fact );
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instEcrire() //   <instEcrire> ::= ecrire ( <expression> | <chaine> )
{
    sauterSymCour ( ECRIRE );
    sauterSymCour ( "(" );
    //if (ls.getSymCour()=="<STRING>") {
    //	Noeud* fact= facteur();
    //}
    //else
    Noeud* exp = expression();
    sauterSymCour ( ")" );
    return new NoeudEcrire ( exp );
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation()
{
// <affectation> ::= <variable> = <expression>
    Noeud* var;
    Noeud* exp;
    testerSymCour ( "<VARIABLE>" );
    if ( ts.variableExiste ( ls.getSymCour() ) )
    {
        var = ts.chercheAjoute ( ls.getSymCour(),ls.getLigne() );
        ls.suivant();
        sauterSymCour ( "=" );
        exp = expBoolOu();

// 		  //  cout << (SymboleValue*)var->SymboleValue::getType() << endl;
// 		    if ((typeid(exp->getValeur()) == typeid(ValeurInt*)))// && (typeid(exp->getValeur()) != typeid(ValeurInt))) {
// 		    		{
// 		    //if (((SymboleValue*)var->getType() == "entier") && (typeid(exp->getValeur()) != typeid(ValeurInt*))) {
// 		   // if (false) {
// 		    cout <<" bonjour " << endl;
// 		    	erreur("Probleme de type ...>");
// 		    }
// 		  //  if (((SymboleValue*)var->getType() == reel) && (typeid(exp->getValeur()) != typeid(ValeurFloat*))) {
// 		    if ((typeid(exp->getValeur()) == typeid(ValeurFloat*)))// && (typeid(exp->getValeur()) != typeid(ValeurFloat*))) {
// 		    		{
// 				cout <<" bonjour " << endl;
// 		    	erreur("Probleme de type ...>");
// 		    }
// 		  //  if (((SymboleValue*)var->getType() == chaine) && (typeid(exp->getValeur()) != typeid(ValeurString*))) {
// 		    if ((typeid(exp->getValeur()) == typeid(ValeurString*)))// && (typeid(exp->getValeur()) != typeid(ValeurString*))) {
// 		    		{
// 				cout <<" bonjour " << endl;
// 		    	erreur("Probleme de type ...>");
// 		    }
    }
    else
        erreur ( "<declarer la varible ...>" );


    return new NoeudAffectation ( var,exp );
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::declaration()
{
    // <declaration> ::= int | float | string | char <variable>
    string type;

    // ls.suivant();
    Noeud* var;
    if ( ls.getSymCour() ==INT )
    {
      type = "entier";
    }
    if ( ls.getSymCour() ==FLOAT)
    {
      type = "reel";
    }
    if (ls.getSymCour() ==STRING)
    {
      type = "chaine";
    }
    if ( ls.getSymCour() ==CHAR )
    {
      type = "chara";
    }
    //  type = operateur
    ls.suivant();
    if ( ! ( ts.variableExiste ( ls.getSymCour() ) ) )
    {
        var = ts.chercheAjoute ( ls.getSymCour(),type,ls.getLigne() );
        ls.suivant();
    }
    else
        erreur ( "<variable deja declarer>" );


    return new NoeudDeclaration ( var,type );
}


////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::expBool()
// <expBool> ::= <relation> { <opBool> <relation> }
{
	if (ls.getSymCour()==NON) {
			sauterSymCour(NON);
	}
	relation();
	while (ls.getSymCour()==ET || ls.getSymCour()==OU) {
		opBool();
		ls.suivant();
		relation();
	}
}*/

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBoolOu()
// <expBool> ::= <expBoolEt> { <opOu> <expBoolOu> }
{
    Noeud* rel = expBoolEt();
    while ( ls.getSymCour() ==OU )
    {
        Symbole operateur = opOu();
        Noeud* relDroit = expBoolEt();
        rel = new NoeudOperateurBinaire ( operateur,rel,relDroit ); // const. du noeud
    }
    return rel;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBoolEt()
// <expBoolEt> ::= <relation> { <opEt> <expBoolOu> }
{
    Noeud* rel = relation();
    while ( ls.getSymCour() ==ET )
    {
        Symbole operateur = opEt();
        Noeud* relDroit = relation();
        rel = new NoeudOperateurBinaire ( operateur,rel,relDroit ); // const. du noeud
    }
    return rel;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::relation()
// <relation> ::= <expBool> { <opRel> <expBool> }
// <expression> { <opRel> <expression> }
{
    Noeud* exp = expression();

    while ( ls.getSymCour() =="==" || ls.getSymCour() =="!=" ||
            ls.getSymCour() =="<" || ls.getSymCour() =="<=" ||
            ls.getSymCour() ==">" || ls.getSymCour() ==">=" )
    {
        //	opRel();
        //	expression();
        Symbole operateur = opRel();
        Noeud* expDroit = expression();
        exp = new NoeudOperateurBinaire ( operateur,exp,expDroit ); // const. du noeud
        /*   if (typeid(exp->getValeur()) != typeid(expDroit->getValeur()))
               erreur("<Comparaison de meme type>");*/
    }
    return exp;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression()
{
// <expression> ::= <terme> { <opAdd> <terme> }
    Noeud* term = terme();
    while ( ls.getSymCour() =="+" || ls.getSymCour() =="-" )
    {
        Symbole operateur =opAdd();
        Noeud* termDroit = terme();
        term = new NoeudOperateurBinaire ( operateur,term,termDroit ); // const. du noeud
        /* if (typeid(term->getValeur()) != typeid(termDroit->getValeur()))
             erreur("<Ajout de meme type>");*/
    }
    return term;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::terme()
{
// <terme> ::= <facteur> { <opBinaire> <facteur> }
    //cout << "trace 2" << endl;
    //facteur();
    Noeud* fact = facteur();
    while ( ls.getSymCour() =="*" || ls.getSymCour() =="/" )
    {
        //opMult();
        //facteur();
        Symbole operateur =opMult(); // on stocke le symbole de l'opérateur
        Noeud* factDroit=facteur(); // lecture de l'operande droit
        fact = new NoeudOperateurBinaire ( operateur,fact,factDroit ); // const. du noeud
        /*   if (typeid(fact->getValeur()) != typeid(factDroit->getValeur()))
               erreur("<Mult de meme type>");*/
    }
    return fact;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur()
{
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )
// <facteur> ::= <entier> | <variable> | <opUnaire> <expBool> | ( <expBool> )

    Noeud* fact=NULL;
    if ( ls.getSymCour() =="<VARIABLE>" || ls.getSymCour() =="<ENTIER>"  || ls.getSymCour() =="<REEL>" || ls.getSymCour() =="<CHAINE>" || ls.getSymCour() =="<CARACT>" )
    {
        fact=ts.chercheAjoute ( ls.getSymCour(),ls.getLigne() );
        ls.suivant();
    }
    else if ( ls.getSymCour() =="-" )
    {
        ls.suivant();
        //opUnaire();
        //	facteur();
        // on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
        fact = new NoeudOperateurBinaire ( Symbole ( "-" ), ts.chercheAjoute ( Symbole ( "0" ) ), facteur());
    }
    else if ( ls.getSymCour() ==NON )
    {
        ls.suivant();
        //	opUnaire();
        //	facteur();
        // cout << "nonononono" << endl;
        fact= ts.chercheAjoute ( Symbole ( "1" ),ls.getLigne() );
        //		  cout << "nonononono" << endl;
        // on représente le nom par une valeur NULL a droite.
        //	fact = new NoeudOperateurBinaire(Symbole(NON), facteur(), fact);
        fact = new NoeudOperateurBinaire ( Symbole ( "!" ), fact, facteur() );
        //  cout << "nonononono" << endl;
    }
    else if ( ls.getSymCour() =="(" )
    {
        ls.suivant();
        fact=expBoolOu();
        sauterSymCour ( ")" );
    }
    else
        erreur ( "<facteur>" );
    return fact;
}


////////////////////////////////////////////////////////////////////////////////
/*void LecteurPhraseSimple::opBinaire()
// <opBinaire> ::= + | - | *  | /
{
	if (ls.getSymCour()=="+" || ls.getSymCour()=="-" ||
		ls.getSymCour()=="*" || ls.getSymCour()=="/")
		ls.suivant();
	else
		erreur("<opBinaire>");
}*/

/*////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseSimple::opBool()
// <opBool> ::= et | ou
{
	if (ls.getSymCour()==ET || ls.getSymCour()==OU)
		ls.suivant();
	else
		erreur("<opBool>");

}*/

////////////////////////////////////////////////////////	return operateur;////////////////////////
Symbole LecteurPhraseAvecArbre::opEt()
// <opBool> ::= et
{
    Symbole operateur;
    if ( ls.getSymCour() ==ET )
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur ( "<opBoolEt" );
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opOu()
// <opBool> ::= ou
{
    Symbole operateur;
    if ( ls.getSymCour() ==OU )
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur ( "<opBoolOu>" );
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opRel()
// <opRel> ::= == | != | < | <= | > | >=
{
    Symbole operateur;
    if ( ls.getSymCour() =="==" || ls.getSymCour() =="!=" ||
         ls.getSymCour() =="<" || ls.getSymCour() =="<=" ||
         ls.getSymCour() ==">" || ls.getSymCour() ==">=" )
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur ( "<opRel>" );
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opUnaire()
// <opUnaire> ::= - | non
{
    Symbole operateur;
    if ( ls.getSymCour() =="-" || ls.getSymCour() ==NON )
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur ( "<opUnaire>" );
    return operateur;

}


////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opAdd()
// <opAdd> ::= + | -
{
    Symbole operateur;
    if ( ls.getSymCour() =="+" || ls.getSymCour() =="-" )
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur ( "<opAdd>" );
    return operateur;
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opMult()
// <opMult> ::= *  | /
{
    Symbole operateur;
    if ( ls.getSymCour() =="*" || ls.getSymCour() =="/" )
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur ( "<opMult>" );
    return operateur;
}


////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::type()
// <type> ::= entier | reel | chaine | caract
{
    Symbole operateur;
    if ( ls.getSymCour() ==INT || ls.getSymCour() ==FLOAT || ls.getSymCour() ==STRING || ls.getSymCour() ==CHAR )
    {
        operateur=ls.getSymCour();
        ls.suivant();
    }
    else
        erreur ( "<type>" );
    return operateur;
}





////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour ( string ch )
{
    if ( ls.getSymCour() != ch )
    {
        cout << endl << "-------- Erreur ligne " << ls.getLigne()
             << " - Colonne " << ls.getColonne() << endl << "   Attendu : "
             << ch << endl << "   Trouve  : " << ls.getSymCour() << endl
             << endl;
        exit ( 0 ); // plus tard, on levera une exception
    }
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour ( string ch )
{
    testerSymCour ( ch );
    ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur ( string mess )
{
    cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
         << ls.getColonne() << endl << "   Attendu : " << mess << endl
         << "   Trouve  : " << ls.getSymCour() << endl << endl;
    exit ( 0 ); // plus tard, on levera une exception
}


